home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / sgi / editors / kali.lha / kali / symmetry.c < prev    next >
C/C++ Source or Header  |  1992-09-14  |  14KB  |  604 lines

  1. /*                        */
  2. /*** symmetry.c - Nina Amenta, Aug. 1989 ****/
  3. /*                        */
  4. #include <math.h>
  5. #include <stdio.h>
  6. #include <gl.h>
  7. #include "symmetry.h"
  8.  
  9. LINE *AddLineToObject();
  10. LINE *AllRotations();
  11. LINE *MakeCurrentObject();
  12. LINE *ReadPattern();
  13. LINE *ReadLine();
  14. POINT ORIGIN = {0.0,0.0};
  15. LINE *NewLine();
  16. void PickLine();
  17. float distance();
  18.  
  19. /* symmetry = 
  20.               admissible transformations
  21.               translation vector1 (screen basis)
  22.               translation vector2 (screen basis)
  23.           #reflections
  24.           reflection vectors  (standard basis)
  25.           glide reflection flag
  26.           #rotations
  27.  
  28. note: the SCREEN basis is the lattice as displayed, ie under user control.
  29. Internally, things assume the STANDARD {1,0},{0,1} basis for the lattice.
  30.  
  31. */
  32. SYMMETRY SYMTAB[NUM_SYM] = {
  33.   {0,{60.0,-103.923},{60.0,103.923},0,
  34.    {{0.0,0.0},{0.0,0.0}},0,3,"p3 - 3-way rotation"},
  35.   {ANG | RAT,{100.0,0.0},{0.0,100.0},0,
  36.    {{0.0,0.0},{0.0,0.0}},0,2,"p2 - 2 way rotation"},
  37.   {ANG | RAT,{100.0,-100.0},{100.0,100.0},0,
  38.    {{0.0,0.0},{0.0,0.0}},0,0,"p1 - translation"},
  39.   {RAT,{100.0,0.0},{0.0,100.0},1,
  40.    {{0.0,0.5},{0.0,0.0}},GLIDE,0,"pg - 1 glide reflection"},
  41.   {RAT,{125.0,0.0},{0.0,125.0},2,
  42.    {{0.5,0.0},{0.0,0.5}},GLIDE,0,"pgg - 2 glide reflections"},
  43.   {RAT,{125.0,0.0},{0.0,125.0},1,
  44.    {{0.0,0.5},{0.0,0.0}},GLIDE,2,"pmg - glide reflection w/ 2-way rotation"},
  45.   {RAT,{125.0,0.0},{0.0,125.0},1,
  46.    {{0.0,0.5},{0.0,0.0}},0,0,"pm - 1 lattice reflection"},
  47.   {ANG,{60.0,-103.923},{60.0,103.923},1,
  48.    {{0.5,0.5},{0.0,0.0}},0,0,"cm - 1 off-lattice reflection"},
  49.   {RAT,{125.0,0.0},{0.0,125.0},1,
  50.    {{0.0,0.5},{0.0,0.0}},0,2,"pmm - 2 lattice reflections"},
  51.   {ANG,{100.0,-100.0},{100.0,100.0},1,
  52.    {{0.5,0.5},{0.0,0.0}},0,2,"cmm - 2 off-lattice reflections"},
  53.   {0,{90.0,-155.884},{90.0,155.884},1,
  54.    {{0.0,0.5},{0.0,0.0}},0,3,"p31m - 3 lattice reflections"},
  55.   {0,{90.0,-155.884},{90.0,155.884},1,
  56.    {{1.0,2.0},{0.0,0.0}},0,3,"p3m1 - 3 off-lattice reflections"},
  57.   {0,{100.0,-100.0},{100.0,100.0},0,
  58.    {{0.0,0.0},{0.0,0.0}},0,4,"p4 - 4-way rotation"},
  59.   {0,{100.0,-100.0},{100.0,100.0},1,
  60.    {{0.5,0.5},{0.0,0.0}},GLIDE,4,"p4g - glide reflection w/ 4-way rotation"},
  61.   {0,{100.0,-100.0},{100.0,100.0},1,
  62.    {{0.5,0.5},{0.0,0.0}},0,4,"p4m - reflection w/ 4-way rotation"},
  63.   {0,{90.0,-155.884},{90.0,155.884},0,
  64.    {{0.0,0.0},{0.0,0.0}},0,6,"p6 - 6-way rotation"},
  65.   {0,{90.0,-155.884},{90.0,155.884},1,
  66.    {{0.0,0.5},{0.0,0.0}},0,6,"p6m - reflection w/ 6-way rotation"}
  67. };
  68.  
  69.  
  70. DefineSymWindow(s_rect,sym,w_rect,scale)
  71. RECTANGLE *w_rect,*s_rect;
  72. SYMMETRY *sym;
  73. float scale;
  74. {
  75.   float x,y;
  76.   VECTOR vec1,vec2;
  77.   extern WINDOW win;
  78.  
  79.   RearrangeVectors(&(sym->v1),&(sym->v2),&vec1,&vec2);
  80.   x = vec1.x + vec2.x;
  81.   y = vec2.y - vec1.y;
  82.   s_rect->width = ((int)(scale*w_rect->width/x) + 1) * x;
  83.   s_rect->height = ((int)(scale*w_rect->height/y) + 1) * y;
  84.   winset(win);
  85.   ortho2(0.0,scale*w_rect->width,0.0,scale*w_rect->height);
  86. }
  87.  
  88.  
  89. int SetUpSymmetry(s,pointpointer,xforms,s_rec)
  90. SYMMETRY *s;
  91. POINT **pointpointer;
  92. XFORM xforms[];
  93. RECTANGLE *s_rec;
  94. {
  95.   int i=0; int j;
  96.   VECTOR vec1,vec2;
  97.   RECTANGLE virtual;
  98.   POINT *pts;
  99.   int maxpts;
  100.  
  101.   virtual.x = virtual.y = 0;
  102.   virtual.width = s_rec->width;
  103.   virtual.height = s_rec->height;
  104.  
  105.   if (*pointpointer != NULL) free(*pointpointer);
  106.   RearrangeVectors(&(s->v1),&(s->v2),&vec1,&vec2);
  107.   maxpts = 2 * (s_rec->width/(vec1.x+vec2.x) + 1) *
  108.        (s_rec->height/(vec2.y-vec1.y) + 1); /* plus 1 for good luck */
  109.   pts = (POINT *)malloc(maxpts*sizeof(POINT));
  110.   *pointpointer = pts;
  111.   pts[0].x = 0.0; pts[0].y = 0.0;
  112.  
  113.   /* lay down points of symmetry */
  114.   for (;;)
  115.     {
  116.       j = i; /* begining of this last row */
  117.       while (RectIncludesPoint(virtual,pts[i]))
  118.     {
  119.       bump(pts+i,pts+i+1,1,&vec1);
  120.       i++;
  121.     }
  122.       bump(pts+j,pts+i,1,&vec2);
  123.       if (PointRightOfRect(pts[i],virtual)) break;
  124.       while (RectIncludesPoint(virtual,pts[i])) 
  125.     bump(pts+i,pts+i,-1,&vec1);
  126.       while (!RectIncludesPoint(virtual,pts[i])) {
  127.     bump(pts+i,pts+i,1,&vec1);
  128.     if (PointRightOfRect(pts[i],virtual)) break;
  129.       }
  130.     }
  131.   SetUpParameterization(&(s->v1),&(s->v2),xforms[3],xforms[4]);
  132.   if (s->rot>1)
  133.     SetUpRot(2.0*M_PI/(s->rot),xforms[0]);
  134.   if (s->refl!=0)
  135.     for (j=0; j<s->refl; j++)
  136.       SetUpRefl(&(s->reflections[j]),xforms[j+1],xforms[3]);
  137.   return(i);
  138. }
  139.  
  140. RearrangeVectors(in1,in2,vec1,vec2)
  141. VECTOR *in1,*in2,*vec1,*vec2;
  142. {
  143.   VECTOR tmp;
  144.   CopyVector(in1,vec1);
  145.   CopyVector(in2,vec2);
  146.   if (vec2->x < 0.0) VectorScalarMult(vec2,-1.0);
  147.   if (vec1->x < 0.0) VectorScalarMult(vec1,-1.0);
  148.   if ((vec1->y > 0.0) && (vec2->y < 0.0)) {
  149.     CopyVector(vec1,&tmp); CopyVector(vec2,vec1); CopyVector(&tmp,vec2);
  150.   }
  151.   while ((vec1->y > 0.0) || (vec2->y < 0.0)) {
  152.     vec2->x = vec1->x - vec2->x;
  153.     vec2->y = vec1->y - vec2->y;
  154.     if (vec2->x < 0.0) VectorScalarMult(vec2,-1.0);
  155.     if ((vec1->y > 0.0) && (vec2->y < 0.0)) {
  156.       CopyVector(vec1,&tmp); CopyVector(vec2,vec1); CopyVector(&tmp,vec2);
  157.     }
  158.   }
  159. }
  160.  
  161. SetUpParameterization(vec1,vec2,std2scr,scr2std)
  162. VECTOR *vec1,*vec2;
  163. XFORM std2scr,scr2std;
  164. {
  165.   std2scr[0] = vec1->x;
  166.   std2scr[1] = vec1->y;
  167.   std2scr[2] = vec2->x;
  168.   std2scr[3] = vec2->y;
  169.   InvertMatrix(std2scr,scr2std);
  170. }
  171.  
  172.  
  173. SetUpRefl(v,xform,std2scr)
  174. VECTOR *v;
  175. XFORM xform,std2scr;
  176. {
  177.   XFORM temp;
  178.   double angle;
  179.   VECTOR w;
  180.  
  181.   /* reflection vector is in standard basis, convert to screen basis */
  182.   VectorMatrixMult(v,std2scr,&w);
  183.   angle=atan2((double)w.y,(double)w.x);
  184.   /* reflection across the x axis */
  185.   temp[0] = 1;
  186.   temp[1] = temp[2] = 0;
  187.   temp[3] = -1; 
  188.   /* rotate to x axis */
  189.   SetUpRot(-angle,xform);
  190.   /* reflect */
  191.   MatrixMultiply(xform,temp,temp);
  192.   /* rotate back */
  193.   SetUpRot(angle,xform);
  194.   MatrixMultiply(temp,xform,xform);
  195. }
  196.  
  197. SetUpRot(angle,xform)
  198. double angle;
  199. float *xform;
  200. {
  201.   xform[1] = sin(angle);
  202.   xform[2] = -sin(angle);
  203.   xform[0] = xform[3] = cos(angle);
  204. }
  205.  
  206. DrawPoints(pts,cnt)
  207. POINT *pts;
  208. int cnt;
  209. {
  210.   int i;
  211.   for (i=0; i<cnt; i++)
  212.       DrawDot(&pts[i]);
  213. }
  214.  
  215.  
  216.  
  217. LINE *MakeCurrentObject(Lines,sym,xforms,bounds)
  218. LINE *Lines;
  219. SYMMETRY *sym;
  220. XFORM xforms[];
  221. RECTANGLE *bounds;
  222. {
  223.   int i,j,pos_count;
  224.   LINE cur,temp,*line_ptr,*obj;
  225.   VECTOR glide[2];
  226.  
  227.     obj = NULL;
  228.     bounds->x = bounds->y = bounds->width = bounds->height = 0.0;
  229.     /* transform glide reflection vectors from standard to current basis */
  230.     if (sym->glide == GLIDE) {
  231.       VectorMatrixMult(&(sym->reflections[0]),xforms[3],&(glide[0]));
  232.       VectorMatrixMult(&(sym->reflections[1]),xforms[3],&(glide[1]));
  233.     }
  234.     else {
  235.       glide[0].x = glide[1].x = glide[0].y = glide[0].y = 0.0;
  236.     }
  237.  
  238.     for (line_ptr=Lines; line_ptr != NULL; line_ptr = line_ptr->next)
  239.     {
  240.     CopyLine(line_ptr,&cur);
  241.     /* Convert from standard basis to screen coordinate basis */
  242.     MatrixMultiply(cur.m,xforms[3],cur.m);
  243.     pos_count = 0;      /* used in picking */
  244.     obj = AllRotations(&cur,xforms[0],sym,obj,bounds,&pos_count);
  245.     if (sym->refl > 0)
  246.     {
  247.         for (i=1; i<=sym->refl; i++)
  248.         {
  249.         temp.id = cur.id;
  250.         MatrixMultiply(cur.m,xforms[i],temp.m);
  251.         TranslateLine(&temp,&(glide[i-1]),1,&temp);
  252.         obj = AllRotations(&temp,xforms[0],sym,obj,bounds,&pos_count);
  253.         if (i==2)
  254.         {
  255.             MatrixMultiply(temp.m,xforms[1],temp.m);
  256.             TranslateLine(&temp,&(glide[0]),1,&temp);
  257.             obj = AllRotations(&temp,xforms[0],sym,obj,bounds,&pos_count);
  258.         }
  259.  
  260.         }
  261.     }
  262.     }
  263.     return(obj);
  264. }
  265.  
  266. FreeObject(obj)
  267. LINE *obj;
  268. {
  269.     LINE *cur;
  270.     while (obj != NULL)
  271.     {
  272.     cur = obj;
  273.     obj = obj->next;
  274.     free(cur);
  275.     }
  276. }
  277.  
  278.  
  279. LINE *AllRotations(l,xform,sym,obj,bounds,pos_count)
  280. LINE *l,*obj;
  281. MATRIX xform;
  282. SYMMETRY *sym;
  283. RECTANGLE *bounds;
  284. int *pos_count;
  285. {
  286.   int j;
  287.   LINE temp;
  288.  
  289.   CopyLine(l,&temp);
  290.   obj = AddLineToObject(obj,&temp,bounds,pos_count);
  291.   for (j=1; j<sym->rot; j++)
  292.     {
  293.       MatrixMultiply(temp.m,xform,temp.m);
  294.       obj = AddLineToObject(obj,&temp,bounds,pos_count);
  295.     }
  296.   return(obj);
  297. }
  298.  
  299. LINE *AddLineToObject(obj,l,r,pos_count)
  300. LINE *obj,*l;
  301. RECTANGLE *r;
  302. int *pos_count;
  303. {
  304.     LINE *new;
  305.     new = NewLine(obj);
  306.     new->obj_pos = (*pos_count)++;
  307.     CopyLine(l,new);    
  308.     AdjustBoundingBox(new,r);
  309.     return(new);
  310. }
  311.  
  312. AdjustBoundingBox(l,r)
  313. LINE *l;
  314. RECTANGLE *r;
  315. {
  316.     float min,max;
  317.     GetMinMax(r->x,r->width,l->m[EX],l->m[SX],&min,&max);
  318.     r->x = min;
  319.     r->width = max;
  320.     GetMinMax(r->y,r->height,l->m[EY],l->m[SY],&min,&max);
  321.     r->y = min;
  322.     r->height = max;
  323. }
  324.  
  325. GetMinMax(a,b,c,d,min,max)
  326. float a,b,c,d,*min,*max;
  327. {
  328.     float tmp;
  329.  
  330.     if (b < a) { tmp=a; a=b; b=tmp;}
  331.     if (c < a) { tmp=a; a=c; c=tmp;}
  332.     if (d < a) { tmp=a; a=d; d=tmp;}
  333.     if (b > d) { tmp=b; b=d; d=tmp;}
  334.     if (c > d) { tmp=c; c=d; d=tmp;}
  335.     *min = a;
  336.     *max = d;
  337. }
  338.  
  339. /* Translate the design to each of the centers of symmetry on the screen,
  340. and draw it. Call ReplicateOffEdges to draw the pieces of designs around
  341. the edges of the picture that belong to centers of symmetry that are just
  342. off the screen. */
  343. ReplicateObject(rect,obj,pts,count,bounds,vec1,vec2,drawing_routine)
  344. RECTANGLE *rect;
  345. LINE *obj;
  346. POINT *pts;
  347. int count;
  348. RECTANGLE *bounds;
  349. VECTOR *vec1,*vec2;
  350. void (*drawing_routine) ();
  351. {
  352.   int i;
  353.  
  354.     for (i=0; i<count; i++)
  355.     {
  356.        /* For picking */
  357.        if (drawing_routine == PickLine)
  358.          LogTranslation(i);
  359.        TranslateCoordinates(pts[i].x,pts[i].y,0.0); 
  360.        DrawObject(obj,drawing_routine);
  361.        ReplicateOffEdges
  362.          (rect,obj,&pts[i],bounds,vec1,vec2,drawing_routine);
  363.  
  364.        TranslateBack();
  365.     }
  366. }
  367.  
  368. /* Rearranges the line so the closest endpoint to the point
  369. is EX,EY */
  370.  
  371. ClosestEndpoint(line,p)
  372. LINE *line;
  373. POINT * p;
  374. {
  375. float temp;
  376.     temp = distance(line->m[EX],line->m[EY],p->x,p->y);
  377.     temp = distance(line->m[SX],line->m[SY],p->x,p->y);
  378.   if (distance(line->m[EX],line->m[EY],p->x,p->y) >
  379.       distance(line->m[SX],line->m[SY],p->x,p->y))
  380.  
  381.     {
  382.       temp = line->m[SX]; line->m[SX] = line->m[EX]; line->m[EX] = temp;
  383.       temp = line->m[SY]; line->m[SY] = line->m[EY]; line->m[EY] = temp;
  384.     }
  385. }
  386.  
  387. float distance(qx,qy,px,py)
  388. float qx,qy,px,py;
  389. {
  390.   float temp;
  391.   temp = sqrt((qx-px)*(qx-px) + (qy-py)*(qy-py));
  392.   return(temp);
  393. }
  394.  
  395. /* Look at all adjacent possible centers of symmetry in the lattice.
  396. If any of these are off the screen, but the current bounding box of
  397. the design intersects the screen, draw the design at that center. 
  398. Then try another step in the same direction. */
  399.  
  400. ReplicateOffEdges(screen,obj,p,bounds,vec1,vec2,drawing_routine)
  401. RECTANGLE *screen;
  402. LINE *obj;
  403. POINT *p;
  404. RECTANGLE *bounds;
  405. VECTOR *vec1,*vec2;
  406. void (*drawing_routine) ();
  407. {
  408. VECTOR v;
  409.  
  410. DrawIfNecessary(screen,obj,p,bounds,vec1,1,vec1,vec2,drawing_routine);
  411. DrawIfNecessary(screen,obj,p,bounds,vec2,1,vec1,vec2,drawing_routine);
  412. DrawIfNecessary(screen,obj,p,bounds,vec1,-1,vec1,vec2,drawing_routine);
  413. DrawIfNecessary(screen,obj,p,bounds,vec2,-1,vec1,vec2,drawing_routine);
  414. AddVector(vec1,vec2,1,&v);
  415. DrawIfNecessary(screen,obj,p,bounds,&v,1,vec1,vec2,drawing_routine);
  416. DrawIfNecessary(screen,obj,p,bounds,&v,-1,vec1,vec2,drawing_routine);
  417. AddVector(vec1,vec2,-1,&v);
  418. DrawIfNecessary(screen,obj,p,bounds,&v,1,vec1,vec2,drawing_routine);
  419. DrawIfNecessary(screen,obj,p,bounds,&v,-1,vec1,vec2,drawing_routine);
  420. }
  421.  
  422. DrawIfNecessary(screen,obj,p,bounds,vec,direction,vec1,vec2,drawing_routine)
  423. RECTANGLE *screen;
  424. LINE *obj;
  425. POINT *p;
  426. RECTANGLE *bounds;
  427. VECTOR *vec,*vec1,*vec2;
  428. int direction;
  429. void (*drawing_routine) ();
  430. {
  431. POINT q;
  432.   bump(p,&q,direction,vec);
  433.   if (!RectIncludesPoint(*screen,q) &&
  434.       BBoxIntersectsRect(&q,bounds,screen)) 
  435.     {
  436.     TranslateCoordinates(direction*vec->x,direction*vec->y,0.0);
  437.     DrawObject(obj,drawing_routine);
  438.     DrawIfNecessary(screen,obj,&q,bounds,vec,direction,
  439.             vec1,vec2,drawing_routine);
  440.     TranslateBack();
  441.   }
  442. }
  443.  
  444.  
  445. int BBoxIntersectsRect(p,bounds,screen)
  446. POINT *p;
  447. RECTANGLE *bounds;
  448. RECTANGLE *screen;
  449. {
  450.   if (((p->x+bounds->width > screen->x) &&
  451.       (p->x+bounds->x < screen->x+screen->width)) &&
  452.       ((p->y+bounds->height > screen->y) &&
  453.        (p->y+bounds->y < screen->y+screen->height))) return(TRUE);
  454.   return(FALSE);
  455. }
  456.  
  457. TranslateLine(s,v,scale,d)
  458. LINE *s,*d;
  459. VECTOR *v;
  460. int scale;
  461. {
  462.   MATRIX temp;
  463.  
  464.   temp[0] = s->m[0]+scale*v->x;
  465.   temp[1] = s->m[1]+scale*v->y;
  466.   temp[2] = s->m[2]+scale*v->x;
  467.   temp[3] = s->m[3]+scale*v->y;
  468.   CopyMatrix(temp,d->m);
  469.   d->id = s->id;
  470. }
  471.  
  472.  
  473. CopyMatrix(f,t)
  474. MATRIX f,t;
  475. {
  476.   int i;
  477.   for (i=0;i<4;i++) t[i]=f[i];
  478. }
  479.  
  480. CopyLine(f,t)
  481. LINE *f,*t;
  482. {
  483.   CopyMatrix(f->m,t->m);
  484.   t->id = f->id;
  485. }
  486.  
  487. CopyVector(v,w)
  488. VECTOR *v,*w;
  489. {
  490.   w->x = v->x; w->y = v->y;
  491. }
  492.  
  493. CopyRectangle(f,t)
  494. RECTANGLE *f,*t;
  495. {
  496.     t->x = f->x; t->y = f->y;
  497.     t->width = f->width; t->height = f->height;
  498. }
  499.  
  500. AddVector(v,w,scale,d)
  501. VECTOR *v,*w,*d;
  502. int scale;
  503. {
  504.   d->x = v->x + scale*w->x;
  505.   d->y = v->y + scale*w->y;
  506. }
  507.  
  508. MatrixMultiply(s,t,d)
  509. MATRIX s,t,d;
  510. {
  511.   MATRIX temp;
  512.   int i;
  513.   temp[0] = s[0]*t[0]+s[1]*t[2];
  514.   temp[1] = s[0]*t[1]+s[1]*t[3];
  515.   temp[2] = s[2]*t[0]+s[3]*t[2];
  516.   temp[3] = s[2]*t[1]+s[3]*t[3];
  517.   CopyMatrix(temp,d);
  518. }
  519.  
  520. VectorMatrixMult(s,m,d)
  521. VECTOR *s,*d;
  522. MATRIX m;
  523. {
  524. VECTOR temp;
  525.   temp.x = s->x*m[0]+s->y*m[2];
  526.   temp.y = s->x*m[1]+s->y*m[3];
  527.   d->x = temp.x; d->y = temp.y;
  528. }
  529.  
  530. VectorScalarMult(v,f)
  531. VECTOR *v;
  532. float f;
  533. {
  534.   v->x *= f; v->y *= f;
  535. }
  536.  
  537. InvertMatrix(s,d)
  538. MATRIX s,d;
  539. {
  540. float det;
  541.   det = s[0]*s[3] - s[1]*s[2];
  542.   d[0] = s[3]/det;
  543.   d[1] = -s[1]/det;
  544.   d[2] = -s[2]/det;
  545.   d[3] = s[0]/det;
  546. }
  547.  
  548.  
  549. NewId(line)
  550. LINE *line;
  551. {
  552.   static short newid=0;
  553.   line->id = newid++;
  554. }
  555.  
  556. LINE *NewLine(Lines)
  557. LINE *Lines;
  558. {
  559.   LINE *new;
  560.   new = (LINE*) malloc(sizeof(LINE));
  561.   new->next = Lines;
  562.   return(new);
  563. }
  564.  
  565.  
  566. LINE *ReadPattern(Lines,pat)
  567. LINE *Lines;
  568. FILE *pat;
  569. {
  570. LINE *cur;
  571. int id=0;
  572.  
  573.   for (cur=ReadLine(pat); cur!=NULL; cur=ReadLine(pat))
  574.     {
  575.     cur->next = Lines;
  576.     cur->id = id++;
  577.     Lines = cur;
  578.     }
  579.   return(Lines);
  580. }
  581.  
  582.  
  583. LINE *ReadLine(pat)
  584. FILE *pat;
  585. {
  586.   LINE *l;
  587.   l = NewLine(NULL);
  588.   if (fscanf(pat,"%f %f %f %f",&l->m[0],&l->m[1],&l->m[2],&l->m[3])!=EOF)
  589.     return (l);
  590.   else 
  591.     {
  592.     free(l);
  593.     return(NULL);
  594.     }
  595. }
  596.  
  597.  
  598.  
  599.  
  600.  
  601.  
  602.  
  603.  
  604.